package com.guchenbo.example.dfs;

import java.util.*;

/**
 * @author guchenbo
 * @date 2024/7/17
 */
public class ParseView2 {
    public static void main(String[] args) {
        List<View> views = mockViews();
        sort(views);
    }

    private static List<View> mockViews() {
        List<View> views = new ArrayList<>();
        for (int i = 0; i < 11; i++) {
            int cnt = i + 1;
            views.add(View.builder().name("v" + cnt).build());
        }
        return views;
    }

    private static void sort(List<View> views) {
        // build tree
        Map<String, TreeView> treeViewMap = new HashMap<>();
        for (View view : views) {
            TreeView treeView = buildTreeView(treeViewMap, view.getName());
            List<String> fromNames = mockFromNames(view.getName());
            if (!fromNames.isEmpty()) {
                treeView.setChildren(new ArrayList<>());
                fromNames.forEach(fromName -> {
                    TreeView fromTreeView = buildTreeView(treeViewMap, fromName);
                    fromTreeView.setRoot(false);
                    treeView.getChildren().add(fromTreeView);
                });
            }
        }
        System.out.println(treeViewMap);

        Set<TreeView> rootTrees = new LinkedHashSet<>();

        treeViewMap.forEach((key, value) -> {
            if (value.isRoot()) {
                rootTrees.add(value);
            }
        });
        System.out.println(rootTrees);

        rootTrees.forEach(view -> {
            List<String> vs = sortTree(view);
            vs.forEach(System.out::println);
        });
    }

    private static List<String> sortTree(TreeView root) {
        List<String> ret = new ArrayList<>();
        Set<String> visited = new HashSet<>();
        Stack<TreeView> stack = new Stack<>();
        stack.push(root);

        while (!stack.isEmpty()) {
            TreeView view = stack.peek();
            List<TreeView> children = view.getChildren();
            if (children == null || children.isEmpty() || visited.contains(view.getName())) {
                stack.pop();
                ret.add(view.getName());
                continue;
            }
            for (int i = children.size() - 1; i >= 0; i--) {
                stack.push(children.get(i));
            }
            visited.add(view.getName());
        }
        return ret;
    }
    private static List<String> mockFromNames(String name) {
        // mock
        if ("v1".equals(name)) {
            return Arrays.asList("v2", "v3");
        } else if ("v2".equals(name)) {
            return Arrays.asList("v4", "v5");
        } else if ("v3".equals(name)) {
            return Arrays.asList("v6", "v7");
        } else if ("v7".equals(name)) {
            return Arrays.asList("v8", "v9", "v10");
        } else if ("v10".equals(name)) {
            return Arrays.asList("v8", "v9", "v11");
        }
        return new ArrayList<>();
    }

    private static TreeView buildTreeView(Map<String, TreeView> treeViewMap, String name) {
        return treeViewMap.computeIfAbsent(name, k -> TreeView.builder().name(k).root(true).build());
    }
}
